import re
from datetime import datetime
import SocketServer.logger as logger
import json
import socket
import threading
import SocketServer.database as mysql_command
import time
class ClientDevice:
    def __init__(self,device,address=None,connected=None,real_address=None,thread=None,demon=None):
        self.device = device
        self.address = address
        self.connected = connected
        self.real_address=real_address
        self.thread=thread
        self.demon=demon
    def addDevice(self,device):
        if self.device==-1:
            self.device=device


class SocketServer():
    server = None
    config = None
    list_connected = {}

    def __init__(self, config):
        self.config = config

    def init(self):
        '''
        服务器初始化
        :return:
        '''
        logger.loginfo("Socket服务初始化")
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.bind((self.config['server_address'], self.config['server_port']))

    def run(self):
        '''
        服务器启动器
        :return:
        '''
        logger.loginfo("Socket服务启动")
        if self.server != None:
            self.server.listen(1000)
            while True:
                connected, address = self.server.accept()
                logger.loginfo("发现设备%s" % (str(address[0]) + ":" + str(address[1])))

                thread = threading.Thread(target=self.update_device_state, args=(connected, address))
                real_address=address[0] + ":" + str(address[1])
                self.list_connected[real_address] = ClientDevice(-1,address,connected,real_address,thread)
                thread.start()
        else:
            raise Exception("You should initation before run server")

    def check_device_state(self,connected,address,real_address):
        logger.loginfo("\033[1;35m %s Time Out\033[0m!" %(real_address))
        #TODO:关闭TCP
        # connected.close()
        if self.list_connected[real_address].device!=-1:
            mysql_command.heart_beat(self.list_connected[real_address].device, 4)

    def update_device_state(self, connected, address):
        '''
        异步设备数据更新处理
        :param connected:
        :param address:
        :return:
        '''
        exit_head=False
        try:
            while True:
                if exit_head:
                    connected.close()
                    break
                real_address = address[0] + ":" + str(address[1])
                try:
                    func = self.check_device_state
                    singal = threading.Timer(5, func, args=(connected,address,real_address))
                    singal.start()
                    buf = connected.recv(2048)
                    singal.cancel()
                    if not buf:
                        connected.close()
                        if self.list_connected[real_address].device!=-1:
                            mysql_command.delete_device(self.list_connected[real_address].device)
                        del self.list_connected[real_address]
                        logger.loginfo("设备%s已中止连接" % (real_address))
                        break
                    buf = str(buf,encoding='utf-8')
                    logger.loginfo("Origin Data %s " %(buf))
                    data=re.findall('{.*?}',buf)
                    logger.loginfo("Regex Data %s " %(data))
                    for real_data in data:
                        head_state, response=None,None
                        try:
                            json_data=json.loads(real_data)
                            head_state, response = self.solve_message(json_data, address, connected,real_address)
                            pass
                        except Exception  as e:
                            logger.logerror("数据处理异常 %s" % e)
                        if response != None:
                            try:
                                self.send_msg_to_client(connected, response)
                            except Exception  as e:
                                logger.logerror("数据发送异常 %s" % e)
                        if head_state == 0x0F:
                            exit_head = True
                except OSError as e:
                    break
                except Exception as e:
                    logger.logerror("设备%s连接异常 %s" % (real_address,e))
                    exit_head=False
                    continue
        except socket.timeout:
            logger.logerror("设备连接%s超时" % address)

    def send_msg_to_client(self, connected, msg):
        '''
        发送数据到设备
        :param connected:
        :param msg:
        :return:
        '''
        connected.send(bytes(msg, encoding="utf8"))

    def solve_message(self, msg, address,connected,real_address):
        '''
        消息处理器
        heaad :
            129:心跳包
            130:电池电量
            131:监测状态信息
            132:注册
            143:退出
        :param msg:
        :return:
        '''
        head = msg['hd']
        device = msg['ID']
        if head == 143:
            logger.loginfo("%s设备退出" % (real_address))
            state = mysql_command.delete_device(device)
            sum = 0x0F + device
            return 0x0F,json.dumps({"hd": 0x0F, "ID": device, "su": sum if sum < 65535 else 0})
        if head == 129:
            logger.loginfo("心跳%s %s" % (address, datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
            self.list_connected[real_address].addDevice(device)
            mysql_command.heart_beat(device, msg['al'])
            sum = 0x01 + device
            return [0x01,json.dumps({"hd": 0x01, "ID": device, "su": sum if sum < 65535 else 0})]
        if head == 131:
            logger.loginfo("状态信息 %s" % datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            mysql_command.device_state(device, msg['vs'], msg['vc'], msg['vt'])
        if head == 130:
            logger.loginfo("电池信息 %s" % datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            mysql_command.update_battery(device, msg['bt'])
        if head == 132:
            logger.loginfo(("设备初始化%s" % real_address))
            state = mysql_command.init_device(device, msg['bn'], msg['ic'], msg['if'], msg['is'])
            sum = 0x02 + device + state
            return [0x02,json.dumps({"hd": 0x02, "ID": device, "fl": state, "su": sum if sum < 65535 else 0})]
        return [None,None]
